package singleton_pattern;


/**
 * 饿汉式 优点：写起来很简单，并且不会因为不加synchronized关键字而造成的线程不安全问题 缺点：当该类被加载的时候，会初始化该实例和静态变量并被创建并分配内存空间，并且会一直占用内存。
 */
class SingletonTest1 {
  private SingletonTest1() {
  }

  private static final SingletonTest1 instance = new SingletonTest1();

  public static SingletonTest1 getInstance() {
    return instance;
  }
}

/**
 * 饱汉式 优点：写起来很简单，在第一次调用的时候才会初始化，节省了内存 缺点：线程不安全， 多个线程调用可能会出现多个实例。 饱汉式可以通过加上synchronized关键字保证线程安全。
 */
class SingletonTest2 {
  private SingletonTest2() {
  }

  private static SingletonTest2 instance;

  public static synchronized SingletonTest2 getInstance() {
    if (instance == null) {
      instance = new SingletonTest2();
    }
    return instance;
  }
}

/**
 * 静态内部类 定义一个私有的构造方法，定义一个该类私有静态的内部类，然后在内部类中定义一个该类的静态变量， 然后通过公共的final修饰的静态方法调用返回实例。因为该类的内部类是私有的，
 * 除了对外公布的公共静态方法getInstance()，是无法访问的。因为它是延迟加载， 所以读取读取实例的时候不会进行同步，几乎没有性能的缺陷，而且还是线程安全的，并且不依赖JDK的版本
 */
class SingletonTest4 {
  private SingletonTest4() {
  }

  private static class SingletonTest5 {
    private static SingletonTest4 instance = new SingletonTest4();
  }

  public static final SingletonTest4 getInstance() {
    System.out.println("调用实例。。。");
    return SingletonTest5.instance;
  }

}

/**
 * 双重锁检查
 */
class SingletonTest6 {
  private SingletonTest6() {
  }

  private static volatile SingletonTest6 instance;

  public static SingletonTest6 getInstance() {
    if (instance == null) {
      synchronized (SingletonTest6.class) {
        if (instance == null) { //防止刚刚开始并发的时候会出现多次初始化
          instance = new SingletonTest6();
        }
      }
    }
    return instance;
  }
}

/**
 * 枚举单例 这种模式在很长的一段时间内可以说是最优的了，内存占用低，效率高，线程安全，多线程操作原子性。 但是有个缺点就是书写麻烦，对新手不太友好。
 */
enum SingletonTest7 {
  INSTANCE;
}


class EnumSingleton {
  private EnumSingleton() {
  }

  public static EnumSingleton getInstance() {
    return Singleton.INSTANCE.getInstance();
  }

  private enum Singleton {

    INSTANCE;
    private EnumSingleton singleton;
    //JVM会保证此方法绝对只会调用一次
    Singleton() {
      singleton = new EnumSingleton();
    }

    public EnumSingleton getInstance() {
      return singleton;
    }
  }

  public static void main(String[] args) {
    EnumSingleton obj1 = EnumSingleton.getInstance();
    EnumSingleton obj2 = EnumSingleton.getInstance();
    System.out.println("obj1=obj2:"+(obj1==obj2));
  }

}















